use axum::{
    Json,
    extract::{Path, State},
    http::StatusCode,
};
use crate::models::item::CreateItem;
use serde_json::Value;
use sqlx::Column;
use sqlx::MySqlPool;
use sqlx::Row;
use std::collections::HashMap;

pub async fn get_items(
    Path(table_name): Path<String>,
    State(pool): State<MySqlPool>,
) -> Json<Vec<Value>> {
    let query = format!("SELECT * FROM {}", table_name);
    let mut items = Vec::new();

    let rows = sqlx::query(&query).fetch_all(&pool).await.unwrap();

    for row in rows {
        let mut item = serde_json::Map::new();
        let columns = row.columns();

        // 确保 id 是第一个键
        if let Some(id_col) = columns.iter().find(|col| col.name() == "id") {
            let id_index = id_col.ordinal();
            let id_value: String = if let Ok(v) = row.try_get::<String, _>(id_index) {
                v
            } else if let Ok(v) = row.try_get::<i32, _>(id_index) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<i64, _>(id_index) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<f32, _>(id_index) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<f64, _>(id_index) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<bool, _>(id_index) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<Option<String>, _>(id_index) {
                v.unwrap_or_default()
            } else {
                continue;
            };
            item.insert("id".to_string(), Value::String(id_value));
            // println!("{}", serde_json::to_string_pretty(&item).unwrap());
        }

        // 插入其他键
        for i in 0..columns.len() {
            let column_name = columns[i].name().to_string();
            if column_name == "id" {
                continue; // id 已经插入
            }
            let value: String = if let Ok(v) = row.try_get::<String, _>(i) {
                v
            } else if let Ok(v) = row.try_get::<i32, _>(i) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<i64, _>(i) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<f32, _>(i) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<f64, _>(i) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<bool, _>(i) {
                v.to_string()
            } else if let Ok(v) = row.try_get::<Option<String>, _>(i) {
                v.unwrap_or_default()
            } else {
                continue;
            };

            item.insert(column_name, Value::String(value));
        }

        items.push(Value::Object(item));
    }

    Json(items)
}

pub async fn create_item(
    Path(table_name): Path<String>,
    State(pool): State<MySqlPool>,
    Json(payload): Json<CreateItem>,
) -> StatusCode {
    let columns = payload.data.keys().cloned().collect::<Vec<_>>().join(", ");
    let values = payload
        .data
        .values()
        .map(|v| format!("'{}'", v)) // 给每个值添加单引号
        .collect::<Vec<_>>()
        .join(", ");
    let query = format!(
        "INSERT INTO {} ({}) VALUES ({})",
        table_name, columns, values
    );
    println!("{}", query);

    sqlx::query(&query).execute(&pool).await.unwrap();

    StatusCode::CREATED
}

pub async fn update_item(
    Path((table_name, id)): Path<(String, i32)>,
    State(pool): State<MySqlPool>,
    Json(payload): Json<HashMap<String, String>>,
) -> StatusCode {
    let updates = payload
        .iter()
        .map(|(k, v)| format!("{} = '{}'", k, v))
        .collect::<Vec<_>>()
        .join(", ");

    let query = format!("UPDATE {} SET {} WHERE id = {}", table_name, updates, id);
    println!("{}", query);
    sqlx::query(&query).execute(&pool).await.unwrap();

    StatusCode::NO_CONTENT
}

pub async fn delete_item(
    Path((table_name, id)): Path<(String, i32)>,
    State(pool): State<MySqlPool>,
) -> StatusCode {
    let query = format!("DELETE FROM {} WHERE id = {}", table_name, id);
    println!("{}", query);
    sqlx::query(&query).execute(&pool).await.unwrap();

    StatusCode::NO_CONTENT
}
